//
//      ┏┛ ┻━━━━━┛ ┻┓
//      ┃　　　　　　 ┃
//      ┃　　　━　　　┃
//      ┃　┳┛　  ┗┳　┃
//      ┃　　　　　　 ┃
//      ┃　　　┻　　　┃
//      ┃　　　　　　 ┃
//      ┗━┓　　　┏━━━┛
//        ┃　　　┃   神兽保佑
//        ┃　　　┃   代码无BUG！
//        ┃　　　┗━━━━━━━━━┓
//        ┃　　　　　　　    ┣┓
//        ┃　　　　         ┏┛
//        ┗━┓ ┓ ┏━━━┳ ┓ ┏━┛
//          ┃ ┫ ┫   ┃ ┫ ┫
//          ┗━┻━┛   ┗━┻━┛
//
// Created by john on 2020/2/5. qq 1612163290
//

#include <stdio.h>
#include <process.h>
#include <ws2tcpip.h>
#include <dirent.h>
#include "ftpserver.h"
#include "socketutil.h"


static int m_socket_cmd;

static int ftp_send_command(int socket_handle, char *cmd) {
    int ret;
    ret = socket_send(socket_handle, cmd, (int) strlen(cmd));
    if (ret < 0) {
        printf("failed to send command: %s", cmd);
        return 0;
    }
    printf("send:%s", cmd);
    return 1;
}


void *thr_fn(void *arg) {
    //数据套接字
    SOCKET data_socket = INVALID_SOCKET;
    //客户端句柄
    SOCKET client_handle = *(SOCKET *) arg;
    char recv_buffer[1024];
    char send_buffer[1024];

    //发送欢迎命令
    char *cmd = "220- Ftp Site Powerd by BigFoolCat Ftp Server 1.0 (meishu1981@gmail.com)\n"
                "220- Welcome to my ftp server\n"
                "220 \r\n";
    sprintf(&send_buffer, "%s", cmd);

    ftp_send_command(client_handle, send_buffer);

    while (1) { //客户端消息循环
        printf("接受到一个连接：%s \r\n", "xxx"/*inet_ntoa(remoteddr.sin_addr)*/);
        int ret = socket_recv(client_handle, recv_buffer, sizeof(recv_buffer));
        if (ret > 0) {
            char left[1024] = {0};
            char right[1024] = {0};
            sscanf(recv_buffer, "%s", left);
            sscanf( recv_buffer+ strlen(left), "%s",right );
            printf("recv:%s %s",left,right);

            if (strcmp(left, "USER") == 0) {
                printf("recv USER");
                sprintf(send_buffer, "331 User name okay, need password.\r\n");
                ftp_send_command(client_handle, send_buffer);
                continue;
            }
            if (strcmp(left, "PASS") == 0) {
                sprintf(send_buffer, "230- anonymous\n"
                                     "230- Ftp server have run for 1h-21m-43s\n"
                                     "230 anonymous logged in.\r\n");
                ftp_send_command(client_handle, send_buffer);
                continue;
            }
            if (strcmp(left, "OPTS") == 0) {
                sprintf(send_buffer, "500 \"OPTS\" :command not understood\r\n");
                ftp_send_command(client_handle, send_buffer);
                continue;
            }
            if (strcmp(left, "QUIT") == 0) {
                sprintf(send_buffer, "221 bye\r\n");
                ftp_send_command(client_handle, send_buffer);
                socket_close(client_handle);
                break;
            }
            if (strcmp(left, "PASV") == 0) {//未实现
                sprintf(send_buffer, "227 Entering Passive Mode (10,0,0,101,241,2)\r\n");
                ftp_send_command(client_handle, send_buffer);
                closesocket(client_handle);
                break;
            }
            if (strcmp(left, "PORT") == 0) {
                //解析ip和端口 新方法
                int a,b,c,d;
                int pa,pb;
                char ip[255];
                int port;
                //char *find = strrchr(cmd,'(');
                sscanf(right,"%d,%d,%d,%d,%d,%d",&a, &b, &c, &d, &pa, &pb);
                sprintf(&ip, "%d.%d.%d.%d", a, b, c, d);
                port = pa * 256 + pb;
                printf("%s:%d\n", ip,port);

                data_socket = socket_create();
                socket_connect(data_socket,ip,port);

                ftp_send_command(client_handle,"200 Port command successful\r\n");
                continue;
                //ip 读取数据
                //port
//                char recvbuf[255];
//
//                do {
//                    iResult = recv(dataSocket, recvbuf, 255, 0);
//                    if (iResult > 0)
//                        printf("Bytes received: %d\n", iResult);
//                    else if (iResult == 0)
//                        printf("Connection closed\n");
//                    else
//                        printf("recv failed: %d\n", WSAGetLastError());
//                } while (iResult > 0);


            }
            if (strcmp(left, "NLST") == 0) {

                ftp_send_command(client_handle,"150 Opening data channel for directory list.\r\n");

                //获取文件列表
                //226 Transfer OK\r\n
                if (data_socket == INVALID_SOCKET) {
                    printf("Unable to connect to client data port!\n");
                    return 1;
                }
                DIR *mydir = NULL;
                struct dirent *myitem = NULL;
                char commd[255] = {0};
                //opendir为用来打开参数name 指定的目录, 并返回DIR*形态的目录流
                if ((mydir = opendir(".")) == NULL) {
                    printf("OpenDir Error!\n");
                    exit(1);
                }

                while ((myitem = readdir(mydir)) != NULL)//用来读取目录,返回是dirent结构体指针
                {
                    if (sprintf(commd, myitem->d_name, 255) < 0)//把文件名写入commd指向的缓冲区
                    {
                        printf("Sprintf Error!\n");
                        exit(1);
                    }
                    strcat(commd, "\r\n");


                    int iResult = socket_send(data_socket, commd, (int) strlen(commd));
                    if (iResult == SOCKET_ERROR) {
                        printf("send failed: %d\n", WSAGetLastError());
                        closesocket(data_socket);
                        return 0;
                    }

//                    if(write(dataSocket, commd, N) < 0 )//将commd缓冲区的内容发送会client
//                    {
//                        printf("Write Error!\n");
//                        exit(1);
//                    }
                }

                closedir(mydir);//关闭目录流
                closesocket(data_socket);

                ftp_send_command(client_handle,"226 Transfer OK\r\n");
                continue;
            }
            //下载文件
            if (strcmp(left, "RETR") == 0) {
                ftp_send_command(client_handle,"150 Opening data channel for file transfer.\r\n");
                //读取文件
                size_t nbytes;
                char buffer[255] = {0};
                printf("get filename : [ %s ]\n", right);
                FILE *fd = fopen(right, "rb");
                if (fd == NULL)//以只读的方式打开client要下载的文件
                {
                    //打开文件错误 写入一个N
                    printf("Open file Error!\n");
                    socket_close(data_socket);
                    return 0;
                }

                //写入正文
                while ((nbytes = fread(buffer, 1, 255, fd)) > 0)//将文件内容读到buffer中
                {
                    int iResult = socket_send(data_socket, buffer, nbytes);
                    if (iResult == SOCKET_ERROR) {
                        printf("send failed: %d\n", WSAGetLastError());
                        closesocket(data_socket);
                        return 0;
                    }
                }

                fclose(fd);
                closesocket(data_socket);

                sprintf(send_buffer, "226 Transfer OK\r\n");
                ftp_send_command(client_handle, send_buffer);
                continue;
            } else {
                sprintf(send_buffer, "220 unkonow:%s OK\r\n",left);
                ftp_send_command(client_handle, send_buffer);
                continue;
            }

        } else {
            sprintf(send_buffer, "221 Goodbye.\r\n");
            ftp_send_command(client_handle, send_buffer);
            socket_close(client_handle);
            break;
        }
    }


    return ((void *) 0);
}


void ftpserver_init() {
    m_socket_cmd = socket_create();
}

void ftpserver_listen(int port) {
    if (socket_listen(m_socket_cmd, port) == 0) {
        printf("ftp listen error\n");
        return;
    }
    printf("ftp listen port:21\n");
    int socket_client;
    struct sockaddr_in remoteddr;
    int addr_len = sizeof(remoteddr);

    //循环接受客户
    while (1) {
        socket_client = socket_accept(m_socket_cmd, &remoteddr, &addr_len);
        if (socket_client == INVALID_SOCKET) {
            break;
        }
        _beginthread(&thr_fn, 0, &socket_client);
        printf("socket_client: %d\n", socket_client);
    }

    socket_close(m_socket_cmd);


}

